<?php
    $STATUS_COLOR = array(
        'Waiting' => '#0000dd',
        'Accepted' => '#ff0000',
        'Wrong Answer' => '#66bb66',
        'Presentation Error' => '#66bb66',
        'Compile Error' => '#66bb66',
        'Time Limit Exceeded' => '#66bb66',
        'Memory Limit Exceeded' => '#66bb66',
        'Output Limit Exceeded' => '#66bb66',
        'Runtime Error' => '#770077',
        'Judging' => '#0000dd',
        '' => '#000000'
    );

function connect_database() {
    $database =  mysql_connect('localhost','felicia','123456789') or die("error connecting localhost\n");
    mysql_select_db('feli') or die("error selecting database\n");
    return $database;
}

function valid_user() {
    session_start();
    if (!isset($_SESSION['user_id']))
        header("Location: login");
}

function valid_contest($contest_id) {
    $database = connect_database();
    $query = "select contest_id from contests where contest_id='" . $contest_id ."'";
    $res = mysql_query($query, $database) or die(mysql_error());
    $row = mysql_fetch_row($res);
    if (empty($row[0]))
        header("Location: error?error=" . urlencode("Contest does not exist"));
}

function login($user_id, $password)	{
    if (empty($user_id) || empty($password))
        return -1;
    $database = connect_database();
    $query = "select password from users where user_id='$user_id'";
    $res = mysql_query($query, $database) or die(mysql_error());
    if (empty($res))
        return -1;
    $row = mysql_fetch_row($res);
    if ($password == $row[0]) {
        $ip = get_ip();
        $now = date("Y-m-d H:i:s");
        $query = "update users set last_login_ip='$ip', last_login_time='$now' where user_id='$user_id'";
        $res = mysql_query($query, $database) or die(mysql_error());
        return 1;
    }
    return -1;
}

function get_user_info($user_id) {
    $database = connect_database();
    $query = "select user_id, password, nickname, email, school from users where user_id='$user_id'";
    $res = mysql_query($query, $database) or die(mysql_error());
    $row = mysql_fetch_assoc($res);
    return $row;
}

function modify_user_profile($user_id, $new_password, $nick, $email, $school) {
    $database = connect_database();
    $query = "update users set password='$new_password', nickname='$nick', email='$email', school='$school' where user_id='$user_id'";
    mysql_query($query, $database) or die(mysql_error());
    return true;
}

function get_contest_info($contest_id) {
    $database = connect_database();
    $query = "select title, start_time, end_time from contests where contest_id='$contest_id'";
    $res = mysql_query($query, $database) or die(mysql_error());
    $row = mysql_fetch_assoc($res);
    return $row;
}

function get_problem_info($contest_id) {
    $database = connect_database();
    $query = "select title, url, as_problem from problems,problems_in_contests where problems_in_contests.problem_id=problems.problem_id and problems_in_contests.contest_id='$contest_id' order by as_problem";
    $res = mysql_query($query, $database) or die(mysql_error());
    $i = 0;
    while ($row = mysql_fetch_assoc($res)) {
        $ret[$i] = $row;
        $i++;
    }
    if (!empty($ret))
        return $ret;
}

function get_contest_title($contest_id) {
    $database = connect_database();
    $query = "select title from contests where contest_id='$contest_id'";
    $res = mysql_query($query, $database) or die(mysql_error());
    $ret = mysql_fetch_row($res);
    return $ret[0];
}

function get_runs($contest_id, $user_id) {
    $database = connect_database();
    $query = "select run_id, as_problem, url, submit_time, result, language from runs, problems,problems_in_contests where problems.problem_id=problems_in_contests.problem_id and problems_in_contests.contest_id='$contest_id' and problems.problem_id=runs.problem_id and runs.contest_id='$contest_id' and runs.user_id='$user_id' order by runs.run_id desc";
    $res = mysql_query($query, $database) or die(mysql_error());
    $i = 0;
    while ($row = mysql_fetch_assoc($res)) {
        $ret[$i] = $row;
        $i++;
    }
    if (!empty($ret))
        return $ret;
}

function submit($contest_id, $user_id, $as_problem, $language, $submit_time, $source) {
    $database = connect_database();
    $query = "select problem_id from problems_in_contests where as_problem='$as_problem' and contest_id='$contest_id'";
    $res = mysql_query($query, $database) or die(mysql_error());
    $row = mysql_fetch_row($res);
    if (empty($row))
        return false;
    $problem_id = $row[0];

    $query = "select end_time from contests where contest_id='$contest_id'";
    $res = mysql_query($query, $database) or die(mysql_error());
    $row = mysql_fetch_assoc($res);
    if (time() > strtotime($row['end_time']))
        return false;
    
    if (get_magic_quotes_gpc()) {
        $source = stripslashes($source);
    }
    $source = mysql_real_escape_string($source);
    $query = "insert into runs (user_id, problem_id, contest_id, submit_time, language, code)
              values ('$user_id', '$problem_id', '$contest_id', '$submit_time', '$language', '$source')";
    $res = mysql_query($query, $database) or die(mysql_error());
	return true;
}

function cmp($a, $b) {
    if ($a['ac_num'][0] > $b['ac_num'][0])
        return -1;
    if ($a['ac_num'][0] < $b['ac_num'][0])
        return 1;
    if ($a['penalty'][0] < $b['penalty'][0])
        return -1;
    if ($a['penalty'][0] > $b['penalty'][0])
        return 1;
    return 0;
}

function get_standing($contest_id) {
    $problem = get_problem_info($contest_id);
	$problem_num = count($problem);

    $database = connect_database();
    
    $query = "select start_time from contests where contest_id='$contest_id'";
    $res0 = mysql_query($query, $database);
    $row0 = mysql_fetch_row($res0);
    $contest_start_time = strtotime($row0[0]);
    
    $query = "select distinct user_id from runs where contest_id='$contest_id'";
    $res0 = mysql_query($query, $database);
    $cnt = 0;
    while ($row0 = mysql_fetch_row($res0)) {
        $user_id = $row0[0];
        
        //get nickname
        $query = "select nickname from users where user_id='$user_id'";
        $res = mysql_query($query, $database);
        $row = mysql_fetch_row($res);
        if (!empty($row[0]))
            $standing_buf[$cnt]['nickname'][0] = $row[0];
        else
            $standing_buf[$cnt]['nickname'][0] = $user_id;
        
        
        //clear
        for ($i = 0; $i < $problem_num; $i++) {
            $standing_buf[$cnt][$problem[$i]['as_problem']][0] = 0;
            $standing_buf[$cnt][$problem[$i]['as_problem']][1] = 0;
        }
        
        //get judged runs
        $query = "select problem_id, submit_time from runs where user_id='$user_id' and
            contest_id='$contest_id' and result<>'Accepted' and result<>'Waiting' and result<>'Judging'";
        $res1 = mysql_query($query, $database);
        while ($row1 = mysql_fetch_row($res1)) {
            $problem_id = $row1[0];
            $submit_time = $row1[1];
            $query = "select as_problem from problems_in_contests where problem_id='$problem_id' and contest_id='$contest_id'";
            $res2 = mysql_query($query, $database);
            $row2 = mysql_fetch_row($res2);
            $as_problem = $row2[0];
            
            $query = "select min(submit_time) from runs where user_id='$user_id' and result='Accepted' and contest_id='$contest_id' and problem_id='$problem_id'
                      group by problem_id";
            $res3 = mysql_query($query, $database);
            $row3 = mysql_fetch_row($res3);
            if (empty($row3[0]) || $submit_time < $row3[0])
                $standing_buf[$cnt][$as_problem][1]++;
        }
        
        //get accepted runs and submit_time
        $query = "select problem_id, min(submit_time) from runs
                  where user_id='$user_id' and result='Accepted' and contest_id='$contest_id'
                  group by problem_id";
        $res1 = mysql_query($query, $database);
        $standing_buf[$cnt]['ac_num'][0] = 0;
        $standing_buf[$cnt]['penalty'][0] = 0;

        while ($row1 = mysql_fetch_row($res1)) {
            $standing_buf[$cnt]['ac_num'][0]++;
            $problem_id = $row1[0];
            $submit_time = strtotime($row1[1]);
            $ac_penalty = floor(($submit_time - $contest_start_time) / 60);
            $query = "select as_problem from problems_in_contests where problem_id='$problem_id' and contest_id='$contest_id'";
            $res2 = mysql_query($query, $database);
            $row2 = mysql_fetch_row($res2);
            $as_problem = $row2[0];
            
            $standing_buf[$cnt][$as_problem][0] = $ac_penalty;
            
            //get other runs and add penalty
            $query = "select count(run_id) from runs where contest_id='$contest_id' and user_id='$user_id' and problem_id='$problem_id'
                      and result<>'Accepted' and result<>'Waiting' and result<>'Judging' and submit_time<'{$row1[1]}'";
            $res3 = mysql_query($query, $database);
            $row3 = mysql_fetch_row($res3);
            $standing_buf[$cnt]['penalty'][0] += $row3[0] * 20;
        }
        
        for ($i = 0; $i < $problem_num; $i++)
            $standing_buf[$cnt]['penalty'][0] +=
                $standing_buf[$cnt][$problem[$i]['as_problem']][0];
        $cnt++;
    }
    if (isset($standing_buf)) {
        usort($standing_buf, 'cmp');
        return $standing_buf;
    }
}

function exist_user($user_id) {
    $database = connect_database();
    $query = "select user_id from users where user_id='$user_id'";
    $res = mysql_query($query, $database) or die(mysql_error());
    $row = mysql_fetch_row($res);
    if (!empty($row[0]))
        return true;
    $query = "select user_id from tmp_users where user_id='$user_id'";
    $res = mysql_query($query, $database) or die(mysql_error());
    $row = mysql_fetch_row($res);
    if (!empty($row[0]))
        return true;
    return false;
}

function register($user_id, $password, $nick, $email, $school) {
    $database = connect_database();
    $query = "insert into tmp_users (user_id, password, nickname, email, school) values ('$user_id', '$password', '$nick', '$email', '$school')";
    $res = mysql_query($query, $database) or die(mysql_error());
    return true;
}

function get_ip() {
	if (getenv('HTTP_CLIENT_IP'))
		 $ip = getenv('HTTP_CLIENT_IP');
	else if (getenv('HTTP_X_FORWARDED_FOR'))
		$ip = getenv('HTTP_X_FORWARDED_FOR');
	else if ($_SERVER['REMOTE_ADDR'])
		$ip = $_SERVER['REMOTE_ADDR'];
	else
		$ip = 'unknow';
	return $ip;
}

function get_code($run_id, $user_id) {
    $database = connect_database();
    $query = "select code, language, submit_time, result from runs where run_id='$run_id' and user_id='$user_id'";
    $res = mysql_query($query, $database) or die(mysql_error());
    $row = mysql_fetch_row($res);
    if (!empty($row[0])) {
        $ret['code'] = $row[0];
        $ret['language'] = $row[1];
        $ret['submit_time'] = $row[2];
        $ret['result'] = $row[3];
        return $ret;
    }
    return "";
}

/**
* IP 地理位置查询类
*
@author 马秉尧
* @version 1.5
* @copyright 2005 CoolCode.CN
. */
class IpLocation {
    /**
     * QQWry.Dat文件指针
     *
     * @var resource
     */
    var $fp;

    /**
     * 第一条IP记录的偏移地址
     *
     * @var int
     */
    var $firstip;

    /**
     * 最后一条IP记录的偏移地址
     *
     * @var int
     */
    var $lastip;

    /**
     * IP记录的总条数（不包含版本信息记录）
     *
     * @var int
     */
    var $totalip;

    /**
     * 返回读取的长整型数
     *
     * @access private
     * @return int
     */
    function getlong() {
        //将读取的little-endian编码的4个字节转化为长整型数
        $result = unpack('Vlong', fread($this->fp, 4));
        return $result['long'];
    }

    /**
     * 返回读取的3个字节的长整型数
     *
     * @access private
     * @return int
     */
    function getlong3() {
        //将读取的little-endian编码的3个字节转化为长整型数
        $result = unpack('Vlong', fread($this->fp, 3).chr(0));
        return $result['long'];
    }

    /**
     * 返回压缩后可进行比较的IP地址
     *
     * @access private
     * @param string $ip
     * @return string
     */
    function packip($ip) {
        // 将IP地址转化为长整型数，如果在PHP5中，IP地址错误，则返回False，
        // 这时intval将Flase转化为整数-1，之后压缩成big-endian编码的字符串
        return pack('N', intval(ip2long($ip)));
    }

    /**
     * 返回读取的字符串
     *
     * @access private
     * @param string $data
     * @return string
     */
    function getstring($data = "") {
        $char = fread($this->fp, 1);
        while (ord($char) > 0) {        // 字符串按照C格式保存，以\0结束
            $data .= $char;             // 将读取的字符连接到给定字符串之后
            $char = fread($this->fp, 1);
        }
        return $data;
    }

    /**
     * 返回地区信息
     *
     * @access private
     * @return string
     */
    function getarea() {
        $byte = fread($this->fp, 1);    // 标志字节
        switch (ord($byte)) {
            case 0:                     // 没有区域信息
                $area = "";
                break;
            case 1:
            case 2:                     // 标志字节为1或2，表示区域信息被重定向
                fseek($this->fp, $this->getlong3());
                $area = $this->getstring();
                break;
            default:                    // 否则，表示区域信息没有被重定向
                $area = $this->getstring($byte);
                break;
        }
        return $area;
    }

    /**
     * 根据所给 IP 地址或域名返回所在地区信息
     *
     * @access public
     * @param string $ip
     * @return array
     */
    function getlocation($ip) {
        if (!$this->fp) return null;            // 如果数据文件没有被正确打开，则直接返回空
        $location['ip'] = gethostbyname($ip);   // 将输入的域名转化为IP地址
        $ip = $this->packip($location['ip']);   // 将输入的IP地址转化为可比较的IP地址
        // 不合法的IP地址会被转化为255.255.255.255
        // 对分搜索
        $l = 0;                         // 搜索的下边界
        $u = $this->totalip;            // 搜索的上边界
        $findip = $this->lastip;        // 如果没有找到就返回最后一条IP记录（QQWry.Dat的版本信息）
        while ($l <= $u) {              // 当上边界小于下边界时，查找失败
            $i = floor(($l + $u) / 2);  // 计算近似中间记录
            fseek($this->fp, $this->firstip + $i * 7);
            $beginip = strrev(fread($this->fp, 4));     // 获取中间记录的开始IP地址
            // strrev函数在这里的作用是将little-endian的压缩IP地址转化为big-endian的格式
            // 以便用于比较，后面相同。
            if ($ip < $beginip) {       // 用户的IP小于中间记录的开始IP地址时
                $u = $i - 1;            // 将搜索的上边界修改为中间记录减一
            }
            else {
                fseek($this->fp, $this->getlong3());
                $endip = strrev(fread($this->fp, 4));   // 获取中间记录的结束IP地址
                if ($ip > $endip) {     // 用户的IP大于中间记录的结束IP地址时
                    $l = $i + 1;        // 将搜索的下边界修改为中间记录加一
                }
                else {                  // 用户的IP在中间记录的IP范围内时
                    $findip = $this->firstip + $i * 7;
                    break;              // 则表示找到结果，退出循环
                }
            }
        }

        //获取查找到的IP地理位置信息
        fseek($this->fp, $findip);
        $location['beginip'] = long2ip($this->getlong());   // 用户IP所在范围的开始地址
        $offset = $this->getlong3();
        fseek($this->fp, $offset);
        $location['endip'] = long2ip($this->getlong());     // 用户IP所在范围的结束地址
        $byte = fread($this->fp, 1);    // 标志字节
        switch (ord($byte)) {
            case 1:                     // 标志字节为1，表示国家和区域信息都被同时重定向
                $countryOffset = $this->getlong3();         // 重定向地址
                fseek($this->fp, $countryOffset);
                $byte = fread($this->fp, 1);    // 标志字节
                switch (ord($byte)) {
                    case 2:             // 标志字节为2，表示国家信息又被重定向
                        fseek($this->fp, $this->getlong3());
                        $location['country'] = $this->getstring();
                        fseek($this->fp, $countryOffset + 4);
                        $location['area'] = $this->getarea();
                        break;
                    default:            // 否则，表示国家信息没有被重定向
                        $location['country'] = $this->getstring($byte);
                        $location['area'] = $this->getarea();
                        break;
                }
                break;
            case 2:                     // 标志字节为2，表示国家信息被重定向
                fseek($this->fp, $this->getlong3());
                $location['country'] = $this->getstring();
                fseek($this->fp, $offset + 8);
                $location['area'] = $this->getarea();
                break;
            default:                    // 否则，表示国家信息没有被重定向
                $location['country'] = $this->getstring($byte);
                $location['area'] = $this->getarea();
                break;
        }
        if ($location['country'] == " CZ88.NET") {  // CZ88.NET表示没有有效信息
            $location['country'] = "未知";
        }
        if ($location['area'] == " CZ88.NET") {
            $location['area'] = "";
        }
        $location['area'] = iconv("GB2312","UTF-8",$location['area']);
        $location['country'] = iconv("GB2312","UTF-8",$location['country']);
        return $location;
    }

    /**
     * 构造函数，打开 QQWry.Dat 文件并初始化类中的信息
     *
     * @param string $filename
     * @return IpLocation
     */
    function IpLocation($filename = "QQWry.Dat") {
        $this->fp = 0;
        if (($this->fp = @fopen($filename, 'rb')) !== false) {
            $this->firstip = $this->getlong();
            $this->lastip = $this->getlong();
            $this->totalip = ($this->lastip - $this->firstip) / 7;
            //注册析构函数，使其在程序执行结束时执行
            register_shutdown_function(array(&$this, '_IpLocation'));
        }
    }

    /**
     * 析构函数，用于在页面执行结束后自动关闭打开的文件。
     *
     */
    function _IpLocation() {
        if ($this->fp) {
            fclose($this->fp);
        }
        $this->fp = 0;
    }
}
?>
